package net.disy.cadenza.repository.wrappers;

import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

import net.disy.cadenza.repository.selector.ResultObjectTypes;
import net.disy.cadenza.repository.workflow.Workflow;
import net.disy.cadenza.schema.selection.Condition;
import net.disy.cadenza.schema.selection.ConditionAttribute;
import net.disy.cadenza.schema.selection.Contains;
import net.disy.cadenza.schema.selection.Default;
import net.disy.cadenza.schema.selection.EntryValue;

public class RepositorySearchResult {
	private Set<Workflow> workflows = new HashSet<Workflow>();
	private Set<SelectorWrapper> selectors = new HashSet<SelectorWrapper>();
	private Set<SelectorCondition> selectorConditions = new HashSet<SelectorCondition>();
	
	private final String CONDITION_ID_TEMPLATE = "Show.RepositoryItem.Condition(%s).Id=%s&";
	private final String CONDITION_ATTRIBUTE_TEMPLATE = "Show.RepositoryItem.Condition(%s).Attribute(%s)=%s&";
	private final String CONDITION_ATTRIBUTE_VALUE_TEMPLATE = "Show.RepositoryItem.Condition(%s).Row(%s).Value(%s)='%s'&";
	
	
	public RepositorySearchResult(Set<Workflow> workflows, Set<SelectorWrapper> selectors, ResultObjectTypes resutlObjectTypes){
		this.workflows = workflows;
		this.selectors = selectors;
		initSelectorConditionsDefaultValues(resutlObjectTypes);
	}
	
	public void merge(RepositorySearchResult repositorySearchResult){
		this.workflows.addAll(repositorySearchResult.getWorkflows());
		this.selectors.addAll(repositorySearchResult.getSelectors());
		if(selectorConditions.size() == 0)
			this.selectorConditions = repositorySearchResult.getSelectorConditions();
		else{
			for(SelectorCondition otherSelectorCondition : repositorySearchResult.getSelectorConditions()){
				SelectorCondition mySelectorCondition = getSelectorCondition(otherSelectorCondition.getConditionName(), otherSelectorCondition.getObjectType());
				if(mySelectorCondition != null){
					if(!mySelectorCondition.equalTo(otherSelectorCondition)){
						for(DefaultConditionValue otherDefaultConditionValue : otherSelectorCondition.getDefaultValues()){
							if(!mySelectorCondition.containsCondition(otherDefaultConditionValue))
								mySelectorCondition.addDefaultValue(otherDefaultConditionValue);
						}
					}
				}else{
					this.selectorConditions.add(otherSelectorCondition);
				}
			}
		}
	}
	
	public Set<String> getSelectorUrlsNotSatisfyingSelectedConditions(){
		Set<String> selectorUrls = new HashSet<String>();
		Set<SelectorCondition> selectedSelectorConditions = getSelectedSelectorConditions();
		for(Workflow workflow : workflows){
			Map<String, Contains> selectorContainsConditions = workflow.getSelector().getContainsConditions();
			for(SelectorCondition selectedSelectorCondition : selectedSelectorConditions){
				Contains selectorContainsForConditionName = selectorContainsConditions.get(selectedSelectorCondition.getConditionName());
				
				if(selectorContainsForConditionName == null){
					selectorUrls.add(workflow.getURL());
					continue;
				}
				List<Default> selectorDefaultValuesForCondition = selectorContainsForConditionName.getCondition().getDefault();
				if(selectorDefaultValuesForCondition.size() != 0){
					for(DefaultConditionValue defaultConditionValue : selectedSelectorCondition.getDefaultValues()){
						if(defaultConditionValue.isEnabled()){
							String selectedAttributeName = defaultConditionValue.getMainAttributeName();
							String selectedAttributeValue = defaultConditionValue.getMainAttributeValue();
							boolean selectorContainsSelectedValue = false;
							for(Default selectorDefault : selectorDefaultValuesForCondition){
								EntryValue selectorEntryValue = selectorDefault.getValue().get(0);
								if(selectorEntryValue.getAttribute().equalsIgnoreCase(selectedAttributeName) && selectorEntryValue.getValue().equalsIgnoreCase(selectedAttributeValue)){
									selectorContainsSelectedValue = true;
									break;
								}
							}
							if(!selectorContainsSelectedValue){
								selectorUrls.add(workflow.getURL());
								break;
							}
						}
					}
				}
			}
		}
		for(SelectorWrapper selector : selectors){
			Map<String, Contains> selectorContainsConditions = selector.getContainsConditions();
			for(SelectorCondition selectedSelectorCondition : selectedSelectorConditions){
				Contains selectorContainsForConditionName = selectorContainsConditions.get(selectedSelectorCondition.getConditionName());
				
				if(selectorContainsForConditionName == null){
					selectorUrls.add(selector.getURL());
					continue;
				}
				List<Default> selectorDefaultValuesForCondition = selectorContainsForConditionName.getCondition().getDefault();
				if(selectorDefaultValuesForCondition.size() != 0){
					for(DefaultConditionValue defaultConditionValue : selectedSelectorCondition.getDefaultValues()){
						if(defaultConditionValue.isEnabled()){
							String selectedAttributeName = defaultConditionValue.getMainAttributeName();
							String selectedAttributeValue = defaultConditionValue.getMainAttributeValue();
							boolean selectorContainsSelectedValue = false;
							for(Default selectorDefault : selectorDefaultValuesForCondition){
								EntryValue selectorEntryValue = selectorDefault.getValue().get(0);
								if(selectorEntryValue.getAttribute().equalsIgnoreCase(selectedAttributeName) && selectorEntryValue.getValue().equalsIgnoreCase(selectedAttributeValue)){
									selectorContainsSelectedValue = true;
									break;
								}
							}
							if(!selectorContainsSelectedValue){
								selectorUrls.add(selector.getURL());
								break;
							}
						}
					}
				}
			}
		}
		return selectorUrls;
	}
	
	private Set<SelectorCondition> getSelectedSelectorConditions(){
		Set<SelectorCondition> selectedSelectorConditions = new HashSet<SelectorCondition>();
		for(SelectorCondition selectorCondition : selectorConditions){
			if(selectorCondition.hasEnabledDefaultValue())
				selectedSelectorConditions.add(selectorCondition);
		}
		return selectedSelectorConditions;
	}
	
	public String getParametersUrl(){
		StringBuffer url = new StringBuffer("");
		int conditionId = 0;
		for(SelectorCondition selectorCondition : getSelectorConditions()){
			if(selectorCondition.hasEnabledDefaultValue()){
				String conditionName = selectorCondition.getConditionName();
				StringBuffer attributesForCondition = new StringBuffer();
				StringBuffer attributeValuesForCondition = new StringBuffer();
				attributesForCondition.append(String.format(CONDITION_ID_TEMPLATE, conditionId, conditionName + ".cnd"));
				int attributeId = 0;
				int rowId = 0;
				for(DefaultConditionValue defaultConditionValue : selectorCondition.getDefaultValues()){
					if(defaultConditionValue.isEnabled()){
						if(attributeId == 0){
							for(String attributeName : defaultConditionValue.getAttributeValues().keySet()){
								attributesForCondition.append(String.format(CONDITION_ATTRIBUTE_TEMPLATE, conditionId, attributeId, attributeName));
								attributeId++;
							}
						}
						Map<String, String> attributeValues = defaultConditionValue.getAttributeValues();
						int valueId = 0;
						for(String attributeName : attributeValues.keySet()){
							String attributeValue = attributeValues.get(attributeName);
							attributeValuesForCondition.append(String.format(CONDITION_ATTRIBUTE_VALUE_TEMPLATE, conditionId, rowId, valueId, attributeValue));
							valueId++;
						}
						rowId++;
					}
				}
				url.append(attributesForCondition).append(attributeValuesForCondition);
				conditionId++;
			}
		}
		String urlStr = url.toString();
		if(urlStr.endsWith("&"))
			urlStr = urlStr.substring(0, urlStr.length() - 1);
		return urlStr;
	}
	
	private SelectorCondition getSelectorCondition(String conditionName, String objectTypeName){
		for(SelectorCondition selectorCondition : selectorConditions){
			if(selectorCondition.getConditionName().equalsIgnoreCase(conditionName) && selectorCondition.getObjectType().equalsIgnoreCase(objectTypeName))
				return selectorCondition;
		}
		return null;
	}
	
	public Set<Workflow> getWorkflows() {
		return workflows;
	}

	public void setWorkflows(Set<Workflow> workflows) {
		this.workflows = workflows;
	}

	public Set<SelectorWrapper> getSelectors() {
		return selectors;
	}

	public void setSelectors(Set<SelectorWrapper> selectors) {
		this.selectors = selectors;
	}

	public Set<SelectorCondition> getSelectorConditions() {
		return selectorConditions;
	}
	
	public Map<String, Set<SelectorCondition>> getSelectorConditionNamesMap() {
		Map<String, Set<SelectorCondition>> selectorConditionNamesMap = new HashMap<String, Set<SelectorCondition>>();
		for(SelectorCondition selectorCondition : selectorConditions){
			Set<SelectorCondition> selectorConditions = selectorConditionNamesMap.get(selectorCondition.getConditionPrintName());
			if(selectorConditions == null){
				selectorConditions = new HashSet<SelectorCondition>();
				selectorConditionNamesMap.put(selectorCondition.getConditionPrintName(), selectorConditions);
			}
			selectorConditions.add(selectorCondition);
		}	
		return selectorConditionNamesMap;
	}

	public void setSelectorConditions(Set<SelectorCondition> selectorConditions) {
		this.selectorConditions = selectorConditions;
	}

	private void initSelectorConditionsDefaultValues(ResultObjectTypes resultObjectTypes){
		Map<String, Contains> containsConditions = getContainsConditions();
		for(String conditionName : containsConditions.keySet()){
			Contains contains = containsConditions.get(conditionName);
			Condition containsCondition = contains.getCondition();
			SelectorCondition selectorCondition = new SelectorCondition(containsCondition.getConditionObjectType().getObjectTypePath(),  conditionName);
			selectorCondition.setConditionPrintName(containsCondition.getPrintName());
			for(ConditionAttribute conditionAttribute : containsCondition.getConditionAttribute()){
				String attributeName = conditionAttribute.getAttributeName();
				List<String> attributeValues = resultObjectTypes.getObjectAttributeToValues().get(attributeName);
				if(attributeValues != null){
					for(int rowId = 0; rowId < attributeValues.size(); rowId++){
						DefaultConditionValue defautlConditionValue = new DefaultConditionValue();
						int conditionAttributePosition = 0;
						for(ConditionAttribute conditionAttributeParam : containsCondition.getConditionAttribute()){
							String attributeNameParam = conditionAttributeParam.getAttributeName();
							List<String> objectAttributeValues = resultObjectTypes.getObjectAttributeToValues().get(attributeNameParam);
							if(objectAttributeValues != null){
								String conditionAttributeValue = objectAttributeValues.get(rowId);
								defautlConditionValue.addAttributeValue(attributeNameParam, conditionAttributeValue);
								if(conditionAttributePosition == 0)
									defautlConditionValue.setMainAttributeName(attributeNameParam);
							}
							conditionAttributePosition++;
						}
						if(defautlConditionValue.getAttributeValues().size() != 0){
							selectorCondition.addDefaultValue(defautlConditionValue);
						}
					}
					break;
				}
				
			}
			if(selectorCondition.getDefaultValues() != null && selectorCondition.getDefaultValues().size() != 0){
				selectorConditions.add(selectorCondition);
			}
		}
	}
	
	private Map<String, Contains> getContainsConditions(){
		Map<String, Contains> containsConditions = new HashMap<String, Contains>();
		for(SelectorWrapper selector : selectors){
			if(selector.isBaseSelector()){
				containsConditions.putAll(selector.getContainsConditions());
			}
		}
		return containsConditions;
	}
	
	public Set<String> getSelectorUrlsSatisfyingSelectorConditions(){
		Set<String> selectorUrls = new HashSet<String>();
		
		return selectorUrls;
	}
	
	public int getResultCount(){
		return selectors.size() + workflows.size();
	}
}
